﻿// =============================================
// 定义头文件保护宏，防止该 Pass 被重复包含（避免编译错误）
// 如果未定义 CUSTOM_LIT_PASS_INCLUDED，则定义它并继续，否则跳过
// =============================================
#ifndef CUSTOM_LIT_PASS_INCLUDED
#define CUSTOM_LIT_PASS_INCLUDED

// =============================================
// 引入自定义 Shader 工具库中的通用功能
// 通常包括：数学工具、常用常量、基础语义定义等
// =============================================
#include "../ShaderLibrary/Common.hlsl"

// =============================================
// 引入 Surface 数据结构的定义
// 通常包括：表面法线、视线方向、颜色、金属度、光滑度、透明度等字段
// 用于在光照计算前统一封装表面信息
// =============================================
#include "../ShaderLibrary/Surface.hlsl"

// =============================================
// 引入光照相关功能，比如光源数据、光源遍历、光照贡献计算等
// =============================================
#include "../ShaderLibrary/Light.hlsl"

// =============================================
// 引入 BRDF（双向反射分布函数）相关功能
// 通常包括：计算漫反射、镜面反射、能量守恒等核心光照模型
// =============================================
#include "../ShaderLibrary/BRDF.hlsl"

// =============================================
// 引入整体 Lighting 逻辑，比如将多个光源的贡献合并、环境光等
// =============================================
#include "../ShaderLibrary/Lighting.hlsl"

// =============================================
// 声明一个 2D 纹理资源，名称为 _BaseMap，通常为物体的基础颜色贴图（Albedo/Diffuse）
// =============================================
TEXTURE2D(_BaseMap);

// =============================================
// 声明一个采样器（SamplerState），名称为 sampler_BaseMap
// 用于定义如何从 _BaseMap 贴图中采样颜色（比如过滤方式、Wrap 模式等）
// =============================================
SAMPLER(sampler_BaseMap);

// =============================================
// 定义一个 Unity Instancing 材质属性缓冲区，名称为 UnityPerMaterial
// 用于存储每个物体（或材质实例）可定制的属性，支持 GPU Instancing 批处理
// 下面定义了贴图变换、基础颜色、透明度裁剪、金属度、光滑度等属性
// =============================================
UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)

	// 贴图的 Tiling（缩放）和 Offset（偏移）参数，float4 格式：(x=scaleX, y=scaleY, z=offsetX, w=offsetY)
	UNITY_DEFINE_INSTANCED_PROP(float4, _BaseMap_ST)

	// 基础颜色（RGBA），用于与贴图相乘后决定物体颜色
	UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)

	// Alpha 裁剪阈值，用于控制 Alpha Test（硬透明），范围 [0,1]
	UNITY_DEFINE_INSTANCED_PROP(float, _Cutoff)

	// PBR 参数：金属度，范围 [0,1]，0 表示非金属，1 表示全金属
	UNITY_DEFINE_INSTANCED_PROP(float, _Metallic)

	// PBR 参数：光滑度，控制镜面高光的锐利程度，范围 [0,1]
	UNITY_DEFINE_INSTANCED_PROP(float, _Smoothness)

// =============================================
// 结束 Unity Instancing 材质属性缓冲区的定义
// =============================================
UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)

// =============================================
// 定义顶点着色器的输入结构体：Attributes
// 包括：物体空间中的顶点位置、法线、第一组 UV、以及 Instancing 实例 ID
// =============================================
struct Attributes {
	float3 positionOS : POSITION;      // 顶点在物体本地空间（Object Space）中的位置
	float3 normalOS : NORMAL;          // 顶点在物体本地空间中的法线方向
	float2 baseUV : TEXCOORD0;         // 第一套 UV，通常用于贴图采样
	UNITY_VERTEX_INPUT_INSTANCE_ID     // 声明该结构体包含一个 Instancing 实例 ID，用于区分不同物体
};

// =============================================
// 定义顶点着色器的输出 / 片段着色器的输入结构体：Varyings
// 包括：裁剪空间中的顶点位置、世界空间中的位置与法线、UV 坐标、以及 Instancing 实例 ID
// =============================================
struct Varyings {
	float4 positionCS : SV_POSITION;   // 顶点在裁剪空间（Clip Space）中的位置，用于屏幕映射和光栅化
	float3 positionWS : VAR_POSITION;  // 顶点在世界空间（World Space）中的位置
	float3 normalWS : VAR_NORMAL;      // 顶点在世界空间中的法线方向
	float2 baseUV : VAR_BASE_UV;       // 传递到片段着色器的 UV 坐标，用于贴图采样
	UNITY_VERTEX_INPUT_INSTANCE_ID     // 传递 Instancing 实例 ID 到片段着色器
};

// =============================================
// 顶点着色器入口函数：LitPassVertex
// 功能：将顶点从物体空间变换到裁剪空间，并计算世界空间位置、法线、UV 变换
// =============================================
Varyings LitPassVertex (Attributes input) {
	Varyings output;
	UNITY_SETUP_INSTANCE_ID(input);               // 初始化当前实例的 ID，必须在访问 Instanced 属性前调用
	UNITY_TRANSFER_INSTANCE_ID(input, output);    // 将当前实例的 ID 从顶点传递到片段着色器

	// 将顶点位置从物体本地空间转换到世界空间
	output.positionWS = TransformObjectToWorld(input.positionOS);

	// 将世界空间坐标转换到裁剪空间（即应用 MVP 变换的最终阶段）
	output.positionCS = TransformWorldToHClip(output.positionWS);

	// 将物体本地法线转换到世界空间法线（用于光照计算中的法线变换）
	output.normalWS = TransformObjectToWorldNormal(input.normalOS);

	// 从 Instancing 缓冲区中获取当前物体的 _BaseMap_ST（贴图 Tiling & Offset）
	float4 baseST = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _BaseMap_ST);

	// 对原始 UV 坐标应用 Tiling (xy) 和 Offset (zw)，计算最终 UV，用于贴图采样
	output.baseUV = input.baseUV * baseST.xy + baseST.zw;

	return output;
}

// =============================================
// 片段着色器入口函数：LitPassFragment
// 功能：采样贴图、构建 Surface 数据、计算光照、返回最终颜色
// 返回值：float4(color, alpha)，即最终渲染颜色
// =============================================
float4 LitPassFragment (Varyings input) : SV_TARGET {
	UNITY_SETUP_INSTANCE_ID(input); // 初始化当前实例 ID，访问 Instanced 属性前必须调用

	// 从 _BaseMap 贴图中采样颜色，使用当前 UV 和采样器
	float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.baseUV);

	// 从 Instancing 缓冲区中获取当前物体的基础颜色
	float4 baseColor = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _BaseColor);

	// 计算基础颜色 = 贴图颜色 × 基础颜色
	float4 base = baseMap * baseColor;

	// 如果定义了 _CLIPPING 宏（通常由材质中启用 Alpha Clipping 控制）
	#if defined(_CLIPPING)
		// 如果当前像素的 Alpha 值 < _Cutoff，则 discard（不渲染该像素）
		// 用于实现硬边缘透明效果，比如铁丝网、叶片等
		clip(base.a - UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Cutoff));
	#endif

	// 构建 Surface 数据结构，用于传递给光照计算函数
	Surface surface;
	surface.normal = normalize(input.normalWS);                         // 归一化世界空间法线
	surface.viewDirection = normalize(_WorldSpaceCameraPos - input.positionWS); // 计算视线方向（摄像机 -> 当前点）
	surface.color = base.rgb;                                            // 基础颜色（RGB）
	surface.alpha = base.a;                                              // 基础透明度（A）
	surface.metallic = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Metallic); // PBR 参数：金属度
	surface.smoothness = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Smoothness); // PBR 参数：光滑度

	// 根据是否启用了 _PREMULTIPLY_ALPHA 宏，选择是否以预乘方式计算 BRDF
	#if defined(_PREMULTIPLY_ALPHA)
		BRDF brdf = GetBRDF(surface, true);  // 启用预乘 Alpha 的 BRDF 计算
	#else
		BRDF brdf = GetBRDF(surface);        // 标准 BRDF 计算
	#endif

	// 计算最终光照颜色（可能包含多个光源、环境光等的贡献）
	float3 color = GetLighting(surface, brdf);

	// 返回最终颜色（包含 RGB 光照结果 + 原始 Alpha）
	return float4(color, surface.alpha);
}

// =============================================
// 结束头文件保护宏
// =============================================
#endif